package com.yunchang.springboot.scheduled.amazon.mws.report.detail;

import com.amazonaws.mws.MarketplaceWebService;
import com.amazonaws.mws.MarketplaceWebServiceClient;
import com.amazonaws.mws.MarketplaceWebServiceConfig;
import com.amazonaws.mws.MarketplaceWebServiceException;
import com.amazonaws.mws.model.*;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.yunchang.springboot.config.MWSReportThrottleConfig;
import com.yunchang.springboot.mapper.base.IBaseMwsReportLogMapper;
import com.yunchang.springboot.mapper.mwsreport.*;
import com.yunchang.springboot.models.Area;
import com.yunchang.springboot.models.Shop;
import com.yunchang.springboot.models.log.BaseMwsReportLogDO;
import com.yunchang.springboot.models.log.LogReportRecord;
import com.yunchang.springboot.models.mwsreportbean.*;
import com.yunchang.springboot.scheduled.amazon.mws.report.common.BaseMwsReport;
import com.yunchang.springboot.scheduled.amazon.mws.report.datadispose.*;
import com.yunchang.springboot.scheduled.amazon.mws.report.save.SaveReportData;
import com.yunchang.springboot.service.mws.report.*;
import com.yunchang.springboot.utils.CryptoUtil;
import com.yunchang.springboot.utils.DateUtil;
import com.yunchang.springboot.utils.file.FilesUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.xml.datatype.XMLGregorianCalendar;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Pattern;

import static com.google.common.collect.Lists.partition;


/**
 * @author chenzw
 * @date 2020/7/31 0031  16:50
 * @description: modified by sjd 2020/8/26
 */
@Component
@Slf4j
public class GetReportProcessDetail extends BaseMwsReport {
    /**
     * 预留库存
     */
    @Resource
    ReservedInventoryDataDispose reservedInventoryDataDispose;

    private IMwsReservedInventoryService iMwsReservedInventoryService;

    @Autowired
    public void setIMwsReservedInventoryService(IMwsReservedInventoryService iMwsReservedInventoryService) {
        this.iMwsReservedInventoryService = iMwsReservedInventoryService;
    }

    /**
     * 在售商品报告
     */
    @Resource
    ActiveListingsReportDataDispose activeListingsReportDataDispose;

    private IMwsActiveListingsReportService iMwsActiveListingsReportService;

    @Autowired
    public void setIMwsActiveListingsReportService(IMwsActiveListingsReportService iMwsActiveListingsReportService) {
        this.iMwsActiveListingsReportService = iMwsActiveListingsReportService;
    }

    /**
     * 所有订单
     */
    @Resource
    AllOrderDataDispose allOrderDataDispose;

    private IMwsAllOrderService iMwsAllOrderService;

    @Autowired
    public void setIMwsAllOrderService(IMwsAllOrderService iMwsAllOrderService) {
        this.iMwsAllOrderService = iMwsAllOrderService;
    }

    /**
     * 已完成订单
     */
    @Resource
    CompleteOrderDataDispose completeOrderDataDispose;

    private IMwsCustomerShipmentSalesService iMwsCustomerShipmentSalesService;

    @Autowired
    public void setIMwsCustomerShipmentSalesService(IMwsCustomerShipmentSalesService iMwsCustomerShipmentSalesService) {
        this.iMwsCustomerShipmentSalesService = iMwsCustomerShipmentSalesService;
    }

    /**
     * 每日库存记录
     */
    @Resource
    EveryDayInventoryRecordsDataDispose everyDayInventoryRecordsDataDispose;

    private IMwsDailyInventoryHistoryService iMwsDailyInventoryHistoryService;

    @Autowired
    public void setIMwsDailyInventoryHistoryService(IMwsDailyInventoryHistoryService iMwsDailyInventoryHistoryService) {
        this.iMwsDailyInventoryHistoryService = iMwsDailyInventoryHistoryService;
    }

    /**
     * 每月库存记录
     */
    @Resource
    EveryMonthInventoryRecordsDataDispose everyMonthInventoryRecordsDataDispose;

    private IMwsMonthlyInventoryHistoryService iMwsMonthlyInventoryHistoryService;

    @Autowired
    public void setIMwsMonthlyInventoryHistoryService(IMwsMonthlyInventoryHistoryService iMwsMonthlyInventoryHistoryService) {
        this.iMwsMonthlyInventoryHistoryService = iMwsMonthlyInventoryHistoryService;
    }

    /**
     * 退货
     */
    @Resource
    FbaCustomerReturnsDataDispose fbaCustomerReturnsDataDispose;

    private IMwsFbaCustomerReturnsService iMwsFbaCustomerReturnsService;

    @Autowired
    public void setIMwsFbaCustomerReturnsService(IMwsFbaCustomerReturnsService iMwsFbaCustomerReturnsService) {
        this.iMwsFbaCustomerReturnsService = iMwsFbaCustomerReturnsService;
    }

    /**
     * 费用预览
     */
    @Resource
    FeePreviewDataDispose feePreviewDataDispose;

    private IMwsFeePreviewService iMwsFeePreviewService;

    @Autowired
    public void setIMwsFeePreviewService(IMwsFeePreviewService iMwsFeePreviewService) {
        this.iMwsFeePreviewService = iMwsFeePreviewService;
    }

    /**
     * 库龄
     */
    @Resource
    InventoryAgeDataDispose inventoryAgeDataDispose;

    private IMwsInventoryAgeService iMwsInventoryAgeService;

    @Autowired
    public void setIMwsInventoryAgeService(IMwsInventoryAgeService iMwsInventoryAgeService) {
        this.iMwsInventoryAgeService = iMwsInventoryAgeService;
    }

    /**
     * 盘库
     */
    @Resource
    InventoryDataDispose inventoryDataDispose;

    private IMwsInventoryAdjustmentsService iMwsInventoryAdjustmentsService;

    @Autowired
    public void setIMwsInventoryAdjustmentsService(IMwsInventoryAdjustmentsService iMwsInventoryAdjustmentsService) {
        this.iMwsInventoryAdjustmentsService = iMwsInventoryAdjustmentsService;
    }

    /**
     * 库存调整
     */
    @Resource
    InventoryReconciliationDataDispose inventoryReconciliationDataDispose;

    private IMwsInventoryReconciliationService iMwsInventoryReconciliationService;

    @Autowired
    public void setIMwsInventoryReconciliationService(IMwsInventoryReconciliationService iMwsInventoryReconciliationService) {
        this.iMwsInventoryReconciliationService = iMwsInventoryReconciliationService;
    }

    /**
     * 库存仓储超量费
     */
    @Resource
    InventoryStorageOverageFeesDataDispose inventoryStorageOverageFeesDataDispose;

    private IMwsInventoryStorageOverageFeesService iMwsInventoryStorageOverageFeesService;

    @Autowired
    public void setIMwsInventoryStorageOverageFeesService(IMwsInventoryStorageOverageFeesService iMwsInventoryStorageOverageFeesService) {
        this.iMwsInventoryStorageOverageFeesService = iMwsInventoryStorageOverageFeesService;
    }

    /**
     * 长期仓储费
     */
    @Resource
    LongTermStorageFeeChargesDataDispose longTermStorageFeeChargesDataDispose;

    private IMwsLongTermStorageFeeChargesService iMwsLongTermStorageFeeChargesService;

    @Autowired
    public void setIMwsLongTermStorageFeeChargesService(IMwsLongTermStorageFeeChargesService iMwsLongTermStorageFeeChargesService) {
        this.iMwsLongTermStorageFeeChargesService = iMwsLongTermStorageFeeChargesService;
    }

    /**
     * 管理亚马逊库存
     */
    @Resource
    ManageFbaInventoryDataDispose manageFbaInventoryDataDispose;

    private IMwsManageFbaInventoryService iMwsManageFbaInventoryService;

    @Autowired
    public void setIMwsManageFbaInventoryService(IMwsManageFbaInventoryService iMwsManageFbaInventoryService) {
        this.iMwsManageFbaInventoryService = iMwsManageFbaInventoryService;
    }

    /**
     * 已接受库存
     */
    @Resource
    ReceiveInventoryDataDispose receiveInventoryDataDispose;

    private IMwsReceiveInventoryService iMwsReceiveInventoryService;

    @Autowired
    public void setIMwsReceiveInventoryService(IMwsReceiveInventoryService iMwsReceiveInventoryService) {
        this.iMwsReceiveInventoryService = iMwsReceiveInventoryService;
    }

    /**
     * 赔偿
     */
    @Resource
    ReimbursementsDataDispose reimbursementsDataDispose;

    private IMwsReimbursementsService iMwsReimbursementsService;

    @Autowired
    public void setIMwsReimbursementsService(IMwsReimbursementsService iMwsReimbursementsService) {
        this.iMwsReimbursementsService = iMwsReimbursementsService;
    }

    /**
     * 移除订单详情
     */
    @Resource
    RemovalOrderDetailDataDispose removalOrderDetailDataDispose;

    private IMwsRemovalOrderDetailService iMwsRemovalOrderDetailService;

    @Autowired
    public void setIMwsRemovalOrderDetailService(IMwsRemovalOrderDetailService iMwsRemovalOrderDetailService) {
        this.iMwsRemovalOrderDetailService = iMwsRemovalOrderDetailService;
    }

    /**
     * 移除货件详情
     */
    @Resource
    RemovalShipmentDetailDataDispose removalShipmentDetailDataDispose;

    private IMwsRemovalShipmentDetailService iMwsRemovalShipmentDetailService;

    @Autowired
    public void setIMwsRemovalShipmentDetailService(IMwsRemovalShipmentDetailService iMwsRemovalShipmentDetailService) {
        this.iMwsRemovalShipmentDetailService = iMwsRemovalShipmentDetailService;
    }

    /**
     * 月存储费用
     */
    @Resource
    MonthlyStorageFeesDataDispose monthlyStorageFeesDataDispose;


    private IMwsMonthlyStorageFeesService iMwsMonthlyStorageFeesService;

    @Autowired
    public void setIMwsMonthlyStorageFeesService(IMwsMonthlyStorageFeesService iMwsMonthlyStorageFeesService) {
        this.iMwsMonthlyStorageFeesService = iMwsMonthlyStorageFeesService;
    }

    @Resource
    IBaseMwsReportLogMapper baseMwsReportLogMapper;

    /**
     * 一次最大插入的数据
     */
    protected static Integer INSERT_MAX_NUM = 10000;

    /**
     * 实时报告下载标识
     */
    final String TIME_SCOPE = "realTime";

    /**
     * 处理日文报告数据编码
     */
    final String CHARSET_NAME_JP = "Shift_JIS";

    /**
     * 报告数据后缀
     */
    final String REPORT_DATA_PATH_SUFFIX = ".txt";

    final String REPORT_BEGIN_TIME = "reportBeginTime";

    final String REPORT_END_TIME = "reportEndTime";

    /**
     * 每日和历史数据的获取报告方式（只执行一次的）
     *
     * @param reportName
     * @param reportInfoId
     * @param reportType
     * @param timeScope
     * @param reportTimeScopeMap
     * @param shopParam
     * @param areaParam
     * @param mwsReportLog
     * @throws Exception
     */
    @Async
    @Transactional
    public void reportDetail(String reportName, Integer reportInfoId, String reportType, String timeScope, Map<String, XMLGregorianCalendar> reportTimeScopeMap, Shop shopParam, Area areaParam, BaseMwsReportLogDO mwsReportLog) throws Exception {
        Thread.currentThread().setName(reportName + "-" + shopParam.getBrandName() + "-" + areaParam.getMwsCountryCode() + "-" + mwsReportLog.getStartDate() + "-" + mwsReportLog.getEndDate());
        log.info("当前线程：" + Thread.currentThread().getName());
        // 先判断进来的日志是否是错误日期再拉取的，如果是，那么则最多循环五次以下代码，直到有一次成功拿到数据
        // 如果不是，那么直接执行一次就行了
        Long parentId = mwsReportLog.getParentId();
        if (parentId != 0) {
            // 说明是错误日志的再拉取流程
            int flag;
            for (int i = 0; i < 5; i++) {
                if (i == 0) {
                    flag = getReportData(reportName, reportInfoId, reportType, timeScope, reportTimeScopeMap, shopParam, areaParam, mwsReportLog);
                } else {
                    //新增一条日志记录
                    BaseMwsReportLogDO childMwsReportLog = new BaseMwsReportLogDO()
                            .setParentId(mwsReportLog.getParentId())
                            .setSellerId(CryptoUtil.encode(shopParam.getSellerId()))
                            .setCountryCode(areaParam.getMwsCountryCode())
                            .setReportInfoId(reportInfoId)
                            .setReportType(reportType)
                            .setAccessMethod(3)
                            .setStartDate(mwsReportLog.getStartDate())
                            .setEndDate(mwsReportLog.getEndDate())
                            .setCreateTime(DateUtil.getNowDateTime())
                            .setModifyTime(DateUtil.getNowDateTime())
                            .setIsDelete(0);
                    saveRequiredNewLog(childMwsReportLog);
                    BaseMwsReportLogDO newMwsReportLog = baseMwsReportLogMapper.selectOne(
                            new LambdaQueryWrapper<BaseMwsReportLogDO>()
                                    .eq(BaseMwsReportLogDO::getParentId, childMwsReportLog.getParentId())
                                    .eq(BaseMwsReportLogDO::getSellerId, childMwsReportLog.getSellerId())
                                    .eq(BaseMwsReportLogDO::getCountryCode, childMwsReportLog.getCountryCode())
                                    .eq(BaseMwsReportLogDO::getReportInfoId, childMwsReportLog.getReportInfoId())
                                    .eq(BaseMwsReportLogDO::getReportType, childMwsReportLog.getReportType())
                                    .eq(BaseMwsReportLogDO::getAccessMethod, childMwsReportLog.getAccessMethod())
                                    .eq(BaseMwsReportLogDO::getStartDate, childMwsReportLog.getStartDate())
                                    .eq(BaseMwsReportLogDO::getEndDate, childMwsReportLog.getEndDate())
                                    .eq(BaseMwsReportLogDO::getCreateTime, childMwsReportLog.getCreateTime())
                                    .eq(BaseMwsReportLogDO::getModifyTime, childMwsReportLog.getModifyTime())
                                    .eq(BaseMwsReportLogDO::getIsDelete, childMwsReportLog.getIsDelete()));
                    flag = getReportData(reportName, reportInfoId, reportType, timeScope, reportTimeScopeMap, shopParam, areaParam, newMwsReportLog);
                }
                if (flag == 1) {
                    break;
                }
            }
        } else {
            getReportData(reportName, reportInfoId, reportType, timeScope, reportTimeScopeMap, shopParam, areaParam, mwsReportLog);
        }
        System.out.println("当前线程：" + Thread.currentThread().getName() + "结束");
    }

    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public int getReportData(String reportName, Integer reportInfoId, String reportType, String timeScope, Map<String, XMLGregorianCalendar> reportTimeScopeMap, Shop shopParam, Area areaParam, BaseMwsReportLogDO mwsReportLog) {
        String sellerId = shopParam.getSellerId();
        String mwsEndPoint = areaParam.getMwsEndPoint();
        try {
            MarketplaceWebServiceConfig config = new MarketplaceWebServiceConfig();
            config.setSoTimeout(6000 * 1000);
            config.setConnectionTimeout(6000 * 1000);
            config.setServiceURL(mwsEndPoint);
            MarketplaceWebService service = new MarketplaceWebServiceClient(
                    shopParam.getAwsAccessKeyId(), shopParam.getSecretKey(), APP_NAME, APP_VERSION, config);
            String mwsAuthToken = shopParam.getMwsAuthToken();
            // 设置marketplaceId参数
            IdList marketplaces = new IdList(Arrays.asList(areaParam.getMarketplaceId()));
            RequestReportRequest requestReportRequest = new RequestReportRequest()
                    .withMerchant(sellerId)
                    .withMarketplaceIdList(marketplaces)
                    .withReportType(reportType)
                    .withMWSAuthToken(mwsAuthToken);
            // 根据reportTimeScopeMap需要设置报告的下载的开始时间和结束时间
            requestReportRequest.setStartDate(reportTimeScopeMap.get(REPORT_BEGIN_TIME));
//            System.out.println(reportTimeScopeMap.get(REPORT_BEGIN_TIME).toString());
            requestReportRequest.setEndDate(reportTimeScopeMap.get(REPORT_END_TIME));
//            System.out.println(reportTimeScopeMap.get(REPORT_END_TIME).toString());
            // 由于reportRequestId在第一次获取后，大部分报告需要在四小时后才会注销之前获得的reportRequestId，
            // 在这期间重新获得的reportRequestId都将是无效的，在之后的获取reportId步骤中将一直返回cancel状态
            // 所以需要先获取相对于当前时间前n小时（据具体报告而定）内有的reportRequestId，有就直接使用，没有则再重新获取reportRequestId
            String reportRequestId = null;
            BaseMwsReportLogDO latestDataInScope = baseMwsReportLogMapper.getLatestDataInScope(reportInfoId, sellerId, areaParam.getMwsCountryCode(), reportType, timeScope, mwsReportLog.getStartDate(), mwsReportLog.getEndDate(), mwsReportLog.getModifyTime());
            if (!(latestDataInScope == null || (latestDataInScope != null && latestDataInScope.getReportRequestId() == null))) {
                reportRequestId = latestDataInScope.getReportRequestId();
            } else {
                //发送RequestReport请求并获取返回值
                log.info("当前线程：" + Thread.currentThread().getName() + "，发送RequestReport请求");
                reportRequestId = getReportRequestId(sellerId, service, requestReportRequest);
            }
            //如果错误，reportRequestId为空，那么更新数据库信息
            if (StringUtils.isEmpty(reportRequestId)) {
                mwsReportLog.setRemark("发送RequestReport请求返回reportRequestId出错！");
                mwsReportLog.setModifyTime(DateUtil.getNowDateTime());
                baseMwsReportLogMapper.updateById(mwsReportLog);
                return 0;
            }
            mwsReportLog.setReportRequestId(reportRequestId);
            // 创建GetReportRequestListRequest对象发送GetReportRequestList请求，获取reportId
            log.info("当前线程：" + Thread.currentThread().getName() + "，发送GetReportRequestList请求");
            String reportId = getReportId(sellerId, reportRequestId, service, mwsAuthToken, mwsReportLog);
            // 根据reportId获得xml文件并读取成list
            List<List<String>> resultList = null;
            if (!("".equals(reportId) || reportId == null)) {
                log.info("当前线程：" + Thread.currentThread().getName() + "，读取xml文件");
                resultList = readXMLToCollection(reportId, sellerId, service, reportName, mwsAuthToken, areaParam, shopParam, mwsReportLog);
                // 获得数据后删除存储在本地的报告数据
                String reportDataPath = reportName + "-" + shopParam.getBrandName() + "-" + areaParam.getMwsCountryCode() + "-" + mwsReportLog.getId() + REPORT_DATA_PATH_SUFFIX;
                FilesUtils.delFilesSpring(reportDataPath);
            }
            if (!(resultList == null || (resultList != null && resultList.size() == 0))) {
                // 将报告对象集合插入对应的表中
                // 根据报告名将报告数据插入对应的表格中
                log.info("当前线程：" + Thread.currentThread().getName() + "，数据入库");
                reportDisposeAndInsertDB(resultList, shopParam.getBrandName(), areaParam.getMwsCountryCode(), reportName, mwsReportLog, sellerId);
                mwsReportLog.setHandleStatus(1);
                mwsReportLog.setModifyTime(DateUtil.getNowDateTime());
                baseMwsReportLogMapper.updateById(mwsReportLog);
                return 1;
            }
        } catch (Exception e) {
            mwsReportLog.setHandleStatus(0);
            mwsReportLog.setRemark("获取报告数据流程中出现问题：" + e);
            mwsReportLog.setModifyTime(DateUtil.getNowDateTime());
            baseMwsReportLogMapper.updateById(mwsReportLog);
            return 0;
        }
        return 0;
    }

    /**
     * 保存需要用到的新的日志记录
     *
     * @param childMwsReportLog
     */
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    void saveRequiredNewLog(BaseMwsReportLogDO childMwsReportLog) {
        baseMwsReportLogMapper.insert(childMwsReportLog);
    }

    /**
     * 获得reportRequestId
     *
     * @param service
     * @param requestReportRequest
     * @return
     * @throws MarketplaceWebServiceException
     */
    public String getReportRequestId(String sellerId, MarketplaceWebService service, RequestReportRequest requestReportRequest) throws MarketplaceWebServiceException {
        //先判断接口的配额是否用完，如果用完则等待一分钟
        String s = CryptoUtil.encode(sellerId);
        while (true) {
            if (MWSReportThrottleConfig.REQUEST_REPORT_THROTTLE_COUNT_MAP.get(s).compareTo(0) == 0) {
                try {
                    Thread.sleep(60000L);
                } catch (InterruptedException e) {
                    log.error("当前线程：" + Thread.currentThread().getName() + "，线程睡眠时出错");
                    e.printStackTrace();
                }
            } else {
                MWSReportThrottleConfig.REQUEST_REPORT_THROTTLE_COUNT_MAP.replace(s, MWSReportThrottleConfig.REQUEST_REPORT_THROTTLE_COUNT_MAP.get(s) - 1);
                System.out.println("当前线程：" + Thread.currentThread().getName() + "的requestReport接口的限额:" + MWSReportThrottleConfig.REQUEST_REPORT_THROTTLE_COUNT_MAP.get(s));
                RequestReportResponse requestReportResponse = service.requestReport(requestReportRequest);
                String reportRequestId = null;
                if (requestReportResponse.isSetRequestReportResult()) {
                    RequestReportResult requestReportResult = requestReportResponse.getRequestReportResult();
                    if (requestReportResult.isSetReportRequestInfo()) {
                        ReportRequestInfo reportRequestInfo = requestReportResult.getReportRequestInfo();
                        if (reportRequestInfo.isSetReportRequestId()) {
                            reportRequestId = reportRequestInfo.getReportRequestId();
                        }
                    }
                }
                return reportRequestId;
            }
        }
    }

    /**
     * 发送GetReportRequestList请求，根据reportProcessingStatus的值判断是否有reportId，返回reportId
     *
     * @param sellerId        卖家id
     * @param reportRequestId reportRequestId
     * @param service         亚马逊提供的接口调用实例MarketplaceWebService
     * @param mwsAuthToken    mwsAuthToken
     * @param mwsReportLog    日志记录对象
     */
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public String getReportId(String sellerId, String reportRequestId, MarketplaceWebService service, String mwsAuthToken, BaseMwsReportLogDO mwsReportLog) throws Exception {
        GetReportRequestListRequest getReportRequestListRequest = new GetReportRequestListRequest();
        getReportRequestListRequest.setMerchant(sellerId);
        getReportRequestListRequest.setMWSAuthToken(mwsAuthToken);
        IdList reportRequestIds = new IdList(Arrays.asList(reportRequestId));
        getReportRequestListRequest.setReportRequestIdList(reportRequestIds);
        // 针对getReportRequestListResponse中的ReportProcessingStatus状态做不同的处理
        String reportProcessingStatus = null;
        GetReportRequestListResponse getReportRequestListResponse;
        do {
            log.info("当前线程：" + Thread.currentThread().getName() + "，重新访问接口，状态码：" + reportProcessingStatus);
            if (reportProcessingStatus != null) {
                threadNeedSleep(50000L);
            }
            //
            getReportRequestListResponse = getReportProcessingStatus(sellerId, getReportRequestListRequest, service);
            reportProcessingStatus = isReportProcessingStatus(getReportRequestListResponse);
            if (StringUtils.isEmpty(reportProcessingStatus)) {
                mwsReportLog.setReportProcessingStatus(reportProcessingStatus);
                mwsReportLog.setRemark("发送GetReportRequestList请求返回的ReportProcessingStatus为空！");
                mwsReportLog.setModifyTime(DateUtil.getNowDateTime());
                baseMwsReportLogMapper.updateById(mwsReportLog);
                break;
            }
            if (reportProcessingStatus.equals(CANCELLED)) {
                mwsReportLog.setReportProcessingStatus(reportProcessingStatus);
                mwsReportLog.setRemark("发送GetReportRequestList请求返回的ReportProcessingStatus是取消！");
                mwsReportLog.setModifyTime(DateUtil.getNowDateTime());
                baseMwsReportLogMapper.updateById(mwsReportLog);
                break;
            }
            if (reportProcessingStatus.equals(DONE_NO_DATA)) {
                mwsReportLog.setReportProcessingStatus(reportProcessingStatus);
                mwsReportLog.setRemark("发送GetReportRequestList请求返回的ReportProcessingStatus是无数据！");
                mwsReportLog.setModifyTime(DateUtil.getNowDateTime());
                mwsReportLog.setHandleStatus(1);
                baseMwsReportLogMapper.updateById(mwsReportLog);
                break;
            }
        }
        while (reportProcessingStatus.equals(SUBMITTED) || reportProcessingStatus.equals(IN_PROGRESS));
        //返回reportId
        String reportId = null;
        if (reportProcessingStatus.equals(DONE)) {
            mwsReportLog.setReportProcessingStatus(reportProcessingStatus);
            if (StringUtils.isEmpty(isGetGeneratedReportId(getReportRequestListResponse))) {
                log.info("当前线程：" + Thread.currentThread().getName() + "，发送getReportList请求");
                GetReportListRequest getReportListRequest = new GetReportListRequest();
                getReportListRequest.setMerchant(sellerId);
                getReportListRequest.setReportRequestIdList(reportRequestIds);
                GetReportListResponse getReportListResponse = getReportList(sellerId, getReportListRequest, service);
                reportId = getReportIdBy(getReportListResponse);
                if (StringUtils.isEmpty(reportId)) {
                    mwsReportLog.setRemark("通过GetReportList获取ReportId为空！");
                    mwsReportLog.setModifyTime(DateUtil.getNowDateTime());
                    baseMwsReportLogMapper.updateById(mwsReportLog);
                    return null;
                }
                mwsReportLog.setReportId(reportId);
                mwsReportLog.setModifyTime(DateUtil.getNowDateTime());
                baseMwsReportLogMapper.updateById(mwsReportLog);
            } else {
                reportId = isGetGeneratedReportId(getReportRequestListResponse);
                mwsReportLog.setGeneratedReportId(reportId);
                mwsReportLog.setModifyTime(DateUtil.getNowDateTime());
                baseMwsReportLogMapper.updateById(mwsReportLog);
            }
        }
        return reportId;
    }

    /**
     * 针对getReportRequestListResponse中的ReportProcessingStatus状态做不同的处理以获取报告
     *
     * @param sellerId
     * @param getReportRequestListRequest
     * @param service
     * @throws Exception
     */
    public GetReportRequestListResponse getReportProcessingStatus(String sellerId, GetReportRequestListRequest getReportRequestListRequest, MarketplaceWebService service) throws Exception {
        // 发送GetReportRequestList请求并获取返回值
        //先判断接口的配额是否用完，如果用完则等待一分钟
        ConcurrentHashMap<String, Integer> getReportRequestListThrottleCountMap = MWSReportThrottleConfig.GET_REPORT_REQUEST_LIST_THROTTLE_COUNT_MAP;
        String s = CryptoUtil.encode(sellerId);
        while (true) {
            if (MWSReportThrottleConfig.GET_REPORT_REQUEST_LIST_THROTTLE_COUNT_MAP.get(s).compareTo(0) == 0) {
                try {
                    Thread.sleep(60000L);
                } catch (InterruptedException e) {
                    log.error("当前线程：" + Thread.currentThread().getName() + "，线程睡眠时出错");
                    e.printStackTrace();
                }
            } else {
                MWSReportThrottleConfig.GET_REPORT_REQUEST_LIST_THROTTLE_COUNT_MAP.replace(s, MWSReportThrottleConfig.GET_REPORT_REQUEST_LIST_THROTTLE_COUNT_MAP.get(s) - 1);
                System.out.println("当前线程：" + Thread.currentThread().getName() + "的getReportRequestList接口的限额:" + MWSReportThrottleConfig.GET_REPORT_REQUEST_LIST_THROTTLE_COUNT_MAP.get(s));
                GetReportRequestListResponse getReportRequestListResponse = service.getReportRequestList(getReportRequestListRequest);
                return getReportRequestListResponse;
            }
        }
    }


    public GetReportListResponse getReportList(String sellerId, GetReportListRequest getReportListRequest, MarketplaceWebService service) throws Exception {
        // 发送GetReportRequestList请求并获取返回值
        //先判断接口的配额是否用完，如果用完则等待一分钟
        ConcurrentHashMap<String, Integer> getReportListThrottleCountMap = MWSReportThrottleConfig.GET_REPORT_LIST_THROTTLE_COUNT_MAP;
        String s = CryptoUtil.encode(sellerId);
        while (true) {
            if (MWSReportThrottleConfig.GET_REPORT_LIST_THROTTLE_COUNT_MAP.get(s).compareTo(0) == 0) {
                try {
                    Thread.sleep(60000L);
                } catch (InterruptedException e) {
                    log.error("当前线程：" + Thread.currentThread().getName() + "，线程睡眠时出错");
                    e.printStackTrace();
                }
            } else {
                MWSReportThrottleConfig.GET_REPORT_LIST_THROTTLE_COUNT_MAP.replace(s, MWSReportThrottleConfig.GET_REPORT_LIST_THROTTLE_COUNT_MAP.get(s) - 1);
                System.out.println("当前线程：" + Thread.currentThread().getName() + "的getReportList接口的限额:" + MWSReportThrottleConfig.GET_REPORT_LIST_THROTTLE_COUNT_MAP.get(s));
                GetReportListResponse getReportListResponse = service.getReportList(getReportListRequest);
                return getReportListResponse;
            }
        }
    }

    /**
     * 调用获取报告getreport接口，获得一个xml文件，读取xml文件解析为list集合
     *
     * @param sellerId
     * @param service
     * @param reportName
     * @param mwsAuthToken
     * @param area
     * @param shop
     * @param mwsReportLog
     * @return
     * @throws MarketplaceWebServiceException
     * @throws FileNotFoundException
     */
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public List<List<String>> readXMLToCollection(String reportId, String sellerId, MarketplaceWebService service, String reportName, String mwsAuthToken, Area area, Shop shop, BaseMwsReportLogDO mwsReportLog) throws MarketplaceWebServiceException, FileNotFoundException {
        List<List<String>> resultList = new ArrayList<>();
        GetReportRequest getReportRequest = new GetReportRequest();
        getReportRequest.setMerchant(sellerId);
        getReportRequest.setMWSAuthToken(mwsAuthToken);
        getReportRequest.setReportId(reportId);
        String reportDataPath = reportName + "-" + shop.getBrandName() + "-" + area.getMwsCountryCode() + "-" + mwsReportLog.getId() + REPORT_DATA_PATH_SUFFIX;
        OutputStream report = new FileOutputStream(reportDataPath);
        getReportRequest.setReportOutputStream(report);
        StringBuffer result = new StringBuffer();
        try {
            // 发送GetReport请求获取报告数据
            getReport(sellerId, getReportRequest, service);
            //构造一个BufferedReader类来读取文件
            FileInputStream fileInputStream = new FileInputStream(reportDataPath);
            InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream, StandardCharsets.UTF_8);
            BufferedReader in = new BufferedReader(inputStreamReader);
            String areaCountryName = area.getMwsCountryCode();
            if (EUROPE_REGION.contains(areaCountryName) || NORTH_AMERICA_REGION.contains(areaCountryName)) {
                inputStreamReader = new InputStreamReader(fileInputStream, StandardCharsets.ISO_8859_1);
                in = new BufferedReader(inputStreamReader);
//                in = new BufferedReader(new InputStreamReader(new FileInputStream(reportDataPath), StandardCharsets.ISO_8859_1));
            }
            if (FAR_EAST_REGION.contains(areaCountryName)) {
                inputStreamReader = new InputStreamReader(fileInputStream, CHARSET_NAME_JP);
                in = new BufferedReader(inputStreamReader);
//                in = new BufferedReader(new InputStreamReader(new FileInputStream(reportDataPath), CHARSET_NAME_JP));
            }
            String s;
            //使用readLine方法，一次读一行
            while ((s = in.readLine()) != null) {
                result.append(System.lineSeparator() + s);
            }
            report.close();
            in.close();
            inputStreamReader.close();
            fileInputStream.close();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {

        }
        String stringResult = result.substring(2);
        String regex = "^<\\?xml version[\\s\\S]*$";
        if (Pattern.matches(regex, stringResult)) {
            mwsReportLog.setXmlStatus(0);
            mwsReportLog.setRemark("处理报告数据时出现错误！");
            mwsReportLog.setModifyTime(DateUtil.getNowDateTime());
            baseMwsReportLogMapper.updateById(mwsReportLog);
            return null;
        }
        String[] rows = stringResult.split("\n");
        for (String row : rows) {
            //-1是为了防止对字符串左右进行去空字符串处理,空字符串为必要数据
            String[] fields = row.replace("\r", "").split("\t", -1);
            resultList.add(Arrays.asList(fields));
        }
        mwsReportLog.setXmlStatus(1);
        mwsReportLog.setRemark("已拿到报告数据，即将将报告数据转化为对象");
        mwsReportLog.setModifyTime(DateUtil.getNowDateTime());
        baseMwsReportLogMapper.updateById(mwsReportLog);
        return resultList;
    }

    public void getReport(String sellerId, GetReportRequest getReportRequest, MarketplaceWebService service) throws Exception {
        // 发送GetReportRequestList请求并获取返回值
        //先判断接口的配额是否用完，如果用完则等待一分钟
        String s = CryptoUtil.encode(sellerId);
        while (true) {
            if (MWSReportThrottleConfig.GET_REPORT_THROTTLE_COUNT_MAP.get(s).compareTo(0) == 0) {
                try {
                    Thread.sleep(60000L);
                } catch (InterruptedException e) {
                    log.error("当前线程：" + Thread.currentThread().getName() + "，线程睡眠时出错");
                    e.printStackTrace();
                }
            } else {
                MWSReportThrottleConfig.GET_REPORT_THROTTLE_COUNT_MAP.replace(s, MWSReportThrottleConfig.GET_REPORT_THROTTLE_COUNT_MAP.get(s) - 1);
                System.out.println("当前线程：" + Thread.currentThread().getName() + "的getReportList接口的限额:" + MWSReportThrottleConfig.GET_REPORT_THROTTLE_COUNT_MAP.get(s));
                service.getReport(getReportRequest);
                return;
            }
        }
    }

    /**
     * 根据reportName将报告数据插入对应的数据库表中
     *
     * @param resultList
     * @param shopBrandName
     * @param areaMwsCountryCode
     * @param reportName
     * @throws Exception
     */
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void reportDisposeAndInsertDB(List<List<String>> resultList, String shopBrandName, String areaMwsCountryCode, String reportName, BaseMwsReportLogDO mwsReportLog, String sellerId) throws Exception {
        List<Object> reportDataList;
        switch (reportName) {
            case "在售商品报告":
                reportDataList = activeListingsReportDataDispose.reportDataDispose(resultList, shopBrandName, areaMwsCountryCode, sellerId);
                List<List<Object>> lists = splitReportData(reportDataList);
                for (List list : lists) {
                    List<MwsActiveListingsReportDO> activeListingsReportDOList = new ArrayList<>(reportDataList.size());
                    for (Object o : list) {
                        activeListingsReportDOList.add((MwsActiveListingsReportDO) o);
                    }
                    iMwsActiveListingsReportService.saveBatch(activeListingsReportDOList, INSERT_MAX_NUM);
                }
                break;
            case "所有订单":
                reportDataList = allOrderDataDispose.reportDataDispose(resultList, shopBrandName, areaMwsCountryCode, sellerId);
                lists = splitReportData(reportDataList);
                for (List list : lists) {
                    List<MwsAllOrderDO> mwsAllOrderDOList = new ArrayList<>(reportDataList.size());
                    for (Object o : list) {
                        mwsAllOrderDOList.add((MwsAllOrderDO) o);
                    }
                    iMwsAllOrderService.saveOrUpdateBatch(mwsAllOrderDOList, INSERT_MAX_NUM);
                }
                break;
            case "已完成订单":
                reportDataList = completeOrderDataDispose.reportDataDispose(resultList, shopBrandName, areaMwsCountryCode, sellerId);
                lists = splitReportData(reportDataList);
                for (List list : lists) {
                    List<MwsCustomerShipmentSalesDO> mwsCustomerShipmentSalesDOList = new ArrayList<>(reportDataList.size());
                    for (Object o : list) {
                        mwsCustomerShipmentSalesDOList.add((MwsCustomerShipmentSalesDO) o);
                    }
                    iMwsCustomerShipmentSalesService.saveBatch(mwsCustomerShipmentSalesDOList, INSERT_MAX_NUM);
                }
                break;
            case "每日库存记录":
                reportDataList = everyDayInventoryRecordsDataDispose.reportDataDispose(resultList, shopBrandName, areaMwsCountryCode, sellerId);
                lists = splitReportData(reportDataList);
                for (List list : lists) {
                    List<MwsDailyInventoryHistoryDO> mwsDailyInventoryHistoryDOList = new ArrayList<>(reportDataList.size());
                    for (Object o : list) {
                        mwsDailyInventoryHistoryDOList.add((MwsDailyInventoryHistoryDO) o);
                    }
                    iMwsDailyInventoryHistoryService.saveBatch(mwsDailyInventoryHistoryDOList, INSERT_MAX_NUM);
                }
                break;
            case "每月库存记录":
                reportDataList = everyMonthInventoryRecordsDataDispose.reportDataDispose(resultList, shopBrandName, areaMwsCountryCode, sellerId);
                lists = splitReportData(reportDataList);
                for (List list : lists) {
                    List<MwsMonthlyInventoryHistoryDO> mwsMonthlyInventoryHistoryDOList = new ArrayList<>(reportDataList.size());
                    for (Object o : list) {
                        mwsMonthlyInventoryHistoryDOList.add((MwsMonthlyInventoryHistoryDO) o);
                    }
                    iMwsMonthlyInventoryHistoryService.saveBatch(mwsMonthlyInventoryHistoryDOList, INSERT_MAX_NUM);
                }
                break;
            case "退货":
                reportDataList = fbaCustomerReturnsDataDispose.reportDataDispose(resultList, shopBrandName, areaMwsCountryCode, sellerId);
                lists = splitReportData(reportDataList);
                for (List list : lists) {
                    List<MwsFbaCustomerReturnsDO> mwsFbaCustomerReturnsDOList = new ArrayList<>(reportDataList.size());
                    for (Object o : list) {
                        mwsFbaCustomerReturnsDOList.add((MwsFbaCustomerReturnsDO) o);
                    }
                    iMwsFbaCustomerReturnsService.saveBatch(mwsFbaCustomerReturnsDOList, INSERT_MAX_NUM);
                }
                break;
            case "费用预览":
                reportDataList = feePreviewDataDispose.reportDataDispose(resultList, shopBrandName, areaMwsCountryCode, sellerId);
                lists = splitReportData(reportDataList);
                for (List list : lists) {
                    List<MwsFeePreviewDO> mwsFeePreviewDOList = new ArrayList<>(reportDataList.size());
                    for (Object o : list) {
                        mwsFeePreviewDOList.add((MwsFeePreviewDO) o);
                    }
                    iMwsFeePreviewService.saveBatch(mwsFeePreviewDOList, INSERT_MAX_NUM);
                }
                break;
            case "库龄":
                reportDataList = inventoryAgeDataDispose.reportDataDispose(resultList, shopBrandName, areaMwsCountryCode, sellerId);
                lists = splitReportData(reportDataList);
                for (List list : lists) {
                    List<MwsInventoryAgeDO> mwsInventoryAgeDOList = new ArrayList<>(reportDataList.size());
                    for (Object o : list) {
                        mwsInventoryAgeDOList.add((MwsInventoryAgeDO) o);
                    }
                    iMwsInventoryAgeService.saveBatch(mwsInventoryAgeDOList, INSERT_MAX_NUM);
                }
                break;
            case "盘库":
                reportDataList = inventoryDataDispose.reportDataDispose(resultList, shopBrandName, areaMwsCountryCode, sellerId);
                lists = splitReportData(reportDataList);
                for (List list : lists) {
                    List<MwsInventoryAdjustmentsDO> mwsInventoryAdjustmentsDOList = new ArrayList<>(reportDataList.size());
                    for (Object o : list) {
                        mwsInventoryAdjustmentsDOList.add((MwsInventoryAdjustmentsDO) o);
                    }
                    iMwsInventoryAdjustmentsService.saveBatch(mwsInventoryAdjustmentsDOList, INSERT_MAX_NUM);
                }
                break;
            case "库存调整":
                reportDataList = inventoryReconciliationDataDispose.reportDataDispose(resultList, shopBrandName, areaMwsCountryCode, sellerId);
                lists = splitReportData(reportDataList);
                for (List list : lists) {
                    List<MwsInventoryReconciliationDO> mwsInventoryReconciliationDOList = new ArrayList<>(reportDataList.size());
                    for (Object o : list) {
                        mwsInventoryReconciliationDOList.add((MwsInventoryReconciliationDO) o);
                    }
                    iMwsInventoryReconciliationService.saveBatch(mwsInventoryReconciliationDOList, INSERT_MAX_NUM);
                }
                break;
            case "库存仓储超量费":
                reportDataList = inventoryStorageOverageFeesDataDispose.reportDataDispose(resultList, shopBrandName, areaMwsCountryCode, sellerId);
                lists = splitReportData(reportDataList);
                for (List list : lists) {
                    List<MwsInventoryStorageOverageFeesDO> mwsInventoryStorageOverageFeesDOList = new ArrayList<>(reportDataList.size());
                    for (Object o : list) {
                        mwsInventoryStorageOverageFeesDOList.add((MwsInventoryStorageOverageFeesDO) o);
                    }
                    iMwsInventoryStorageOverageFeesService.saveBatch(mwsInventoryStorageOverageFeesDOList, INSERT_MAX_NUM);
                }
                break;
            case "长期仓储费":
                reportDataList = longTermStorageFeeChargesDataDispose.reportDataDispose(resultList, shopBrandName, areaMwsCountryCode, sellerId);
                lists = splitReportData(reportDataList);
                for (List list : lists) {
                    List<MwsLongTermStorageFeeChargesDO> mwsLongTermStorageFeeChargesDOList = new ArrayList<>(reportDataList.size());
                    for (Object o : list) {
                        mwsLongTermStorageFeeChargesDOList.add((MwsLongTermStorageFeeChargesDO) o);
                    }
                    iMwsLongTermStorageFeeChargesService.saveBatch(mwsLongTermStorageFeeChargesDOList, INSERT_MAX_NUM);
                }
                break;
            case "管理亚马逊库存":
                reportDataList = manageFbaInventoryDataDispose.reportDataDispose(resultList, shopBrandName, areaMwsCountryCode, sellerId);
                lists = splitReportData(reportDataList);
                for (List list : lists) {
                    List<MwsManageFbaInventoryDO> mwsManageFbaInventoryDOList = new ArrayList<>(reportDataList.size());
                    for (Object o : list) {
                        mwsManageFbaInventoryDOList.add((MwsManageFbaInventoryDO) o);
                    }
                    iMwsManageFbaInventoryService.saveBatch(mwsManageFbaInventoryDOList, INSERT_MAX_NUM);
                }
                break;
            case "已接收库存":
                reportDataList = receiveInventoryDataDispose.reportDataDispose(resultList, shopBrandName, areaMwsCountryCode, sellerId);
                lists = splitReportData(reportDataList);
                for (List list : lists) {
                    List<MwsReceiveInventoryDO> mwsReceiveInventoryDOList = new ArrayList<>(reportDataList.size());
                    for (Object o : list) {
                        mwsReceiveInventoryDOList.add((MwsReceiveInventoryDO) o);
                    }
                    iMwsReceiveInventoryService.saveBatch(mwsReceiveInventoryDOList, INSERT_MAX_NUM);
                }
                break;
            case "赔偿":
                reportDataList = reimbursementsDataDispose.reportDataDispose(resultList, shopBrandName, areaMwsCountryCode, sellerId);
                lists = splitReportData(reportDataList);
                for (List list : lists) {
                    List<MwsReimbursementsDO> mwsReimbursementsDOList = new ArrayList<>(reportDataList.size());
                    for (Object o : list) {
                        mwsReimbursementsDOList.add((MwsReimbursementsDO) o);
                    }
//                        System.out.println(mwsReimbursementsDOList.toString());
                    iMwsReimbursementsService.saveBatch(mwsReimbursementsDOList, INSERT_MAX_NUM);
                }
                break;
            case "移除订单详情":
                reportDataList = removalOrderDetailDataDispose.reportDataDispose(resultList, shopBrandName, areaMwsCountryCode, sellerId);
                lists = splitReportData(reportDataList);
                for (List list : lists) {
                    List<MwsRemovalOrderDetailDO> mwsRemovalOrderDetailDOList = new ArrayList<>(reportDataList.size());
                    for (Object o : list) {
                        mwsRemovalOrderDetailDOList.add((MwsRemovalOrderDetailDO) o);
                    }
                    iMwsRemovalOrderDetailService.saveOrUpdateBatch(mwsRemovalOrderDetailDOList, INSERT_MAX_NUM);
                }
                break;
            case "移除货件详情":
                reportDataList = removalShipmentDetailDataDispose.reportDataDispose(resultList, shopBrandName, areaMwsCountryCode, sellerId);
                lists = splitReportData(reportDataList);
                for (List list : lists) {
                    List<MwsRemovalShipmentDetailDO> mwsRemovalShipmentDetailDOList = new ArrayList<>(reportDataList.size());
                    for (Object o : list) {
                        mwsRemovalShipmentDetailDOList.add((MwsRemovalShipmentDetailDO) o);
                    }
                    iMwsRemovalShipmentDetailService.saveBatch(mwsRemovalShipmentDetailDOList, INSERT_MAX_NUM);
                }
                break;
            case "预留库存":
                reportDataList = reservedInventoryDataDispose.reportDataDispose(resultList, shopBrandName, areaMwsCountryCode, sellerId);
                lists = splitReportData(reportDataList);
                for (List list : lists) {
                    List<MwsReservedInventoryDO> mwsReservedInventoryDOList = new ArrayList<>(reportDataList.size());
                    for (Object o : list) {
                        mwsReservedInventoryDOList.add((MwsReservedInventoryDO) o);
                    }
                    iMwsReservedInventoryService.saveBatch(mwsReservedInventoryDOList, INSERT_MAX_NUM);
                }
                break;
            case "月储存费用":
                reportDataList = monthlyStorageFeesDataDispose.reportDataDispose(resultList, shopBrandName, areaMwsCountryCode, sellerId);
                lists = splitReportData(reportDataList);
                for (List list : lists) {
                    List<MwsMonthlyStorageFeesDO> mwsMonthlyStorageFeesDOList = new ArrayList<>(reportDataList.size());
                    for (Object o : list) {
                        mwsMonthlyStorageFeesDOList.add((MwsMonthlyStorageFeesDO) o);
                    }
                    iMwsMonthlyStorageFeesService.saveBatch(mwsMonthlyStorageFeesDOList, INSERT_MAX_NUM);
                }
                break;
        }
    }


    /**
     * 将报告数据转换为指定大小的多个集合
     *
     * @param insertList
     */
    public List<List<Object>> splitReportData(List<Object> insertList) {
        List<List<Object>> subsectionResultList = new ArrayList<>();
        if (null != insertList && !insertList.isEmpty()) {
            if (insertList.size() > INSERT_MAX_NUM) {
                // 将insertList数量大于INSERT_MAX_NUM的进行切割并返回数量为INSERT_MAX_NUM大小的集合
                subsectionResultList = partition(insertList, INSERT_MAX_NUM);
                return subsectionResultList;
            } else {
                subsectionResultList.add(insertList);
                return subsectionResultList;
            }
        } else {
            return null;
        }
    }
}
